
#ifndef RTUTILTEMPLATES_H
#define RTUTILTEMPLATES_H

#include "RtThreadManager.h"
#include "RtReferenceControl.h"
#include "RtTimerWrapper.h"
#include "RtTimeValue.h"

/**
 * @class CRtSingletonT
 *
 * @brief A Singleton Adapter uses the Adapter pattern to turn ordinary
 * classes into Singletons optimized with the Double-Checked
 * Locking optimization pattern.
 */
template <class Type> 
class CRtSingletonT : public CRtCleanUpBase
{
public:
	static Type* Instance() 
	{
		static CRtSingletonT<Type> *s_pInstance = NULL;
		if (!s_pInstance) {
			MutexType *pMutex = NULL;
			CRtThreadManager::Instance()->GetSingletonMutex(pMutex);
			if (pMutex) {
				CRtMutexGuardT<MutexType> theGuard(*pMutex);
				if (!s_pInstance) {
					s_pInstance = new CRtSingletonT<Type>();
				}
			}
			RT_ASSERTE(s_pInstance);
		}
		return &s_pInstance->m_Instance;
	}
	
protected:
	CRtSingletonT() { }
	virtual ~CRtSingletonT() { }
	Type m_Instance;

private:
	typedef CRtMutexThreadRecursive MutexType;
	
	// = Prevent assignment and initialization.
	void operator = (const CRtSingletonT&);
	CRtSingletonT(const CRtSingletonT&);
};

template <class DeleteType>
class CRtEventDeleteT : public IRtEvent
{
public:
	CRtEventDeleteT(DeleteType *aDelete)
		: m_pDeleteType(aDelete)
		, m_bHaveDeleted(FALSE)
		, m_bHaveLaunched(FALSE)
	{
		RT_ASSERTE(m_pDeleteType);
		RT_ASSERTE(static_cast<void*>(aDelete) != static_cast<void*>(this));
	}

	virtual ~CRtEventDeleteT() 
	{
		if (!m_bHaveDeleted) {
			m_bHaveDeleted = TRUE;
			delete m_pDeleteType;
		}
	}

	RtResult Launch(CRtThread* aThread)
	{
		RT_ASSERTE_RETURN(aThread, RT_ERROR_INVALID_ARG);
		RT_ASSERTE_RETURN(!m_bHaveLaunched, RT_ERROR_ALREADY_INITIALIZED);
		m_bHaveLaunched = TRUE;

		RtResult rv = RT_ERROR_NULL_POINTER;
		IRtEventQueue *pEq = aThread->GetEventQueue();
		if (pEq) {
			rv = pEq->PostEvent(this);
		}
		
		if (RT_FAILED(rv)) {
			RT_ERROR_TRACE("CRtEventDeleteT::Launch, PostEvent() failed! rv=" << rv);
		}
		return rv;
	}

	virtual RtResult OnEventFire()
	{
//		RT_ASSERTE(0 == m_pDeleteType->GetReference());
		RT_ASSERTE(m_bHaveLaunched);

		RT_ASSERTE(!m_bHaveDeleted);
		m_bHaveDeleted = TRUE;
		delete m_pDeleteType;
//		m_pDeleteType = NULL;
		return RT_OK;
	}

private:
	DeleteType *m_pDeleteType;
	BOOL m_bHaveDeleted;
	BOOL m_bHaveLaunched;
};

template <class DeleteType>
class CRtTimerDeleteT : public IRtTimerHandler
{
public:
	CRtTimerDeleteT(DeleteType *aDelete)
		: m_pDeleteType(aDelete)
		, m_bHaveLaunched(FALSE)
	{
		RT_ASSERTE(m_pDeleteType);
		RT_ASSERTE(static_cast<void*>(aDelete) != static_cast<void*>(this));
	}
	
	virtual ~CRtTimerDeleteT() 
	{
	}

	RtResult Launch()
	{
		RT_ASSERTE_RETURN(!m_bHaveLaunched, RT_ERROR_ALREADY_INITIALIZED);
		m_bHaveLaunched = TRUE;
		
		IRtTimerQueue *pTimerQueue = NULL;
		CRtThread* pThread = 
			CRtThreadManager::Instance()->GetThread(CRtThreadManager::TT_CURRENT);
		if (pThread)
			pTimerQueue = pThread->GetTimerQueue();
		
		RtResult rv = RT_ERROR_NULL_POINTER;
		if (pTimerQueue) {
			// can't use CRtTimeValue::s_tvZero due to it is not exported. strange!
			rv = pTimerQueue->ScheduleTimer(this, NULL, CRtTimeValue(), 1);
			if (rv == RT_ERROR_FOUND)
				rv = RT_OK;
		} 

		if (RT_FAILED(rv)) {
			RT_ERROR_TRACE("CRtTimerDeleteT::Launch, ScheduleTimer() failde! rv=" << rv);
		}
		return rv;
	}
	
	virtual void OnTimeout(const CRtTimeValue &, LPVOID aArg)
	{
//		RT_ASSERTE(0 == m_pDeleteType->GetReference());
		RT_ASSERTE(m_bHaveLaunched);

		delete m_pDeleteType;
//		m_pDeleteType = NULL;
	}
	
private:
	DeleteType *m_pDeleteType;
	BOOL m_bHaveLaunched;
};

template <class MutexType>
class CRtReferenceControlTimerDeleteT 
	: public CRtReferenceControlT<MutexType>
{
public:
	CRtReferenceControlTimerDeleteT()
		: m_Delete(this)
	{
	}

	virtual ~CRtReferenceControlTimerDeleteT() { }

protected:
	virtual void OnReferenceDestory()
	{
#ifdef RT_DEBUG
		//RtResult rv = 
#endif // RT_DEBUG
			m_Delete.Launch();

		// the thread is stopped if rv == RT_ERROR_NOT_INITIALIZED.
		//RT_ASSERTE(RT_SUCCEEDED(rv) || rv == RT_ERROR_NOT_INITIALIZED);
		//disable up to fix bug 171368, because the thread already remove from thread manager(swap!)
	}

private:
	CRtTimerDeleteT<CRtReferenceControlTimerDeleteT> m_Delete;
	friend class CRtTimerDeleteT<CRtReferenceControlTimerDeleteT>;
};

typedef CRtReferenceControlTimerDeleteT<CRtMutexNullSingleThread> CRtReferenceControlSingleThreadTimerDelete;
typedef CRtReferenceControlTimerDeleteT<CRtMutexThread> CRtReferenceControlMutilThreadTimerDelete;

#endif // !RTUTILTEMPLATES_H
